/**
 * @file w5100_cc2530.h
 * @brief Declares constants and operations that pertain to the w5100 ethernet
 *        device, but are specific to how the W5100 interfaces with the CC2530
 *        chip in the Wizi project. 
 *
 * @author Vamshi Ponnapalli
 */

#ifndef _W5100_WIZI_H
  #define _W5100_WIZI_H
  /*****************************************************************************
   * Includes
   ****************************************************************************/
  #include "hal_defs.h"
  #include "ioCC2530.h"

  #ifdef __cplusplus
    extern "C" {
  #endif

  /*****************************************************************************
  * Constants - schematic for details
  * https://greece.ccs.neu.edu/wiki/doku.php?id=cc2530
  * Schematic: 
  * https://greece.ccs.neu.edu/pool/cc2530_prototypes/CC2530_ethgateway.sch
  *****************************************************************************/ 
  //Data port and direction settings
  #define W5100_DATA_PORT          P1
  #define W5100_DATA_PORT_NUM      1
  #define W5100_DATA_MODE          P1DIR
  
  //Data port direction values
  #define W5100_DATA_MODE_WRITE    0xFF
  #define W5100_DATA_MODE_READ     0x00

  //Control port and direction settings
  #define W5100_CONTROL_PORT       P0
  #define W5100_CONTROL_PORT_NUM   0
      
  //Reset. Set 0 to activate 
  #define W5100_RESET_PIN          P0_0
  #define W5100_RESET_PIN_NUM      0
  #define W5100_RESET_BIT          BIT0

  //Address 0 pin    
  #define W5100_ADDR0_PIN          P0_1
  #define W5100_ADDR0_PIN_NUM      1
  #define W5100_ADDR0_BIT          BIT1 
  
  //Address 1 pin
  #define W5100_ADDR1_PIN          P0_2
  #define W5100_ADDR1_PIN_NUM      2
  #define W5100_ADDR1_BIT          BIT2 

  //Set to 0 in order to read/write from the ethernet device. This must be
  //used in conjunction with the read/write pins
  #define W5100_CHIPSEL_PIN        P0_3
  #define W5100_CHIPSEL_PIN_NUM    3
  #define W5100_CHIPSEL_BIT        BIT3

  //Set to 0 in order to read from the ethernet device
  #define W5100_READ_PIN           P0_5
  #define W5100_READ_PIN_NUM       5
  #define W5100_READ_BIT           BIT5

  //Set to 0 in order to write to the ethernet device
  #define W5100_WRITE_PIN          P0_7
  #define W5100_WRITE_PIN_NUM      7
  #define W5100_WRITE_BIT          BIT7
  
  //Set to 1 if an ethernet event occurs
  #define W5100_INTERRUPT_PIN      P0_6
  #define W5100_INTERRUPT_PIN_NUM  6
  #define W5100_INTERRUPT_BIT      BIT6 
        
  //Bit mask required for write enablement
  #define W5100_WRITE_ENABLE_BM    W5100_CHIPSEL_BIT |\
                                                      W5100_WRITE_BIT

  //Bit mask required for read enablement
  #define W5100_READ_ENABLE_BM     W5100_CHIPSEL_BIT |\
                                                      W5100_READ_BIT
  /*****************************************************************************
   * Function declarations
   ****************************************************************************/
  /**
   * Resets the W5100 ethernet device.
   */
  void w5100_reset(void);

  /**
   * Sets the addressing mode on the W5100.
   * 
   * @param mode The addressing mode to set.
   */
  void w5100_setAddressingMode(uint8 mode);

  /**
   * Sets the interrupt mask on the W5100.
   * 
   * @param mask The interrupt mask to set.
   */
  void w5100_setInterruptMask(uint8 mask);

  /**
   * Initializes socket Tx memory and addressing parameters on the ethernet
   * device. Each socket could have different buffer sizes based on the input 
   * parameters passed.
   *
   * @param s0Size Size specification for socket 0
   * @param s1Size Size specification for socket 1
   * @param s2Size Size specification for socket 2
   * @param s3Size Size specification for socket 3
   */
  void w5100_initializeTxMemory(uint8 s0Size, uint8 s1Size, 
                                                    uint8 s2Size, uint8 s3Size);

  /**
   * Initializes socket Rx memory and addressing parameters on the ethernet
   * device. Each socket could have different buffer sizes based on the input 
   * parameters passed.
   *
   * @param s0Size Size specification for socket 0
   * @param s1Size Size specification for socket 1
   * @param s2Size Size specification for socket 2
   * @param s3Size Size specification for socket 3
   */
  void w5100_initializeRxMemory(uint8 s0Size, uint8 s1Size, 
                                                    uint8 s2Size, uint8 s3Size);

  /**
   * Sets the MAC address on the ethernet device. It is assumed that the MAC 
   * address is 6 bytes long.
   *
   * @param macAddress The MAC address to set.
   */
  void w5100_setMacAddress(mac_address_t macAddress);

  /**
   * Sets the local IP address on the ethernet device. 
   *
   * @param ipAddress The IP address to set.
   */
  void w5100_setLocalIPAddress(ip_address_t ipAddress);

  /**
   * Sets the remote IP address for a specific socket.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param ipAddress The IP address to set.
   */
  void w5100_setRemoteIPAddress(uint8 socket, ip_address_t ipAddress);

  /**
   * Sets the local port number for a specific socket. 
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param portNumber A pointer to the IP address. The first 6 bytes of this
   *                  buffer will be used as the IP address.
   */
  void w5100_setLocalPortNumber(uint8 socket, uint16 portNumber);

  /**
   * Sets the remote port number for a specific socket. 
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param portNumber A pointer to the IP address. The first 6 bytes of this
   *                  buffer will be used as the IP address.
   */
  void w5100_setRemotePortNumber(uint8 socket, uint16 portNumber);

  /**
   * Gets the current state of the specified socket.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   *
   * @return The state of the socket.
   */
  uint8 w5100_getSocketState(uint8 socket);
  
  /**
   * Opens a socket under the specified mode. This can be one of the accepted 
   * mode values ETHERNET_SOCK_MODE_TCP, ETHERNET_SOCK_MODE_UDP, etc.
   * 
   * A socket must be opened before a connection based protocol (ex:TCP) can be
   * initiated.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param mode The mode to open the socket in.
   */
  void w5100_openSocket(uint8 socket, uint8 mode);

  /**
   * Closes an existing socket.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   */
  void w5100_closeSocket(uint8 socket);

  /**
   * Writes data to the transmit buffer of a specific socket and issues a send
   * command.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param data A pointer to the data to be transmitted.
   * @param size The size of the data to be transmitted.
   *
   * @return SUCCESS if the operation was completed successfully, FAILED 
   *         otherwise. Note that a SUCCESS message only means that the steps
   *         for a send operation were completed without error. It does not
   *         indicate that the data was successfully received by the remote 
   *         host.
   */
  uint8 w5100_Transmit(uint8 socket, uint8 *pData, uint16 size);
  
  /**
   * Reads a specified number of bytes from the receive buffer of a specific
   * socket. This function will receive data that has been sent to the device.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param data A pointer to the data to be received.
   * @param size The size of the data to be received.
   *
   * @return SUCCESS if the operation was completed successfully, FAILED 
   *         otherwise. 
   */
  uint8 w5100_Receive(uint8 socket, uint8 *pData, uint16 size);

  /**
   * Reads the state of the ethernet interrupts. This operation automatically
   * clears the flags after they have been read.
   *
   * @return The state of the ethernet interrupt flags.
   */
  uint8 w5100_getEthernetEventState(void);
  
  /**
   * Reads the state of the socket interrupts for a specific socket. This
   * operation automatically clears the flags after they have been read.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @return The state of the socket interrupt flags.
   */
  uint8 w5100_getSocketEventState(uint8 socket);

  /**
   * Returns the number of bytes that are still to be read from a specific 
   * socket's rx buffer.
   * 
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   *
   * @return The number of bytes that are available for reading.
   */
  uint16 w5100_getAvailableDataSize(uint8 socket);

  /**
   * Sets the subnet mask on the ethernet device.
   *
   * @param mask The subnet mask to set.
   */
  void w5100_setSubnetMask(ip_address_t mask);
  
  /**
   * Sets the gateway IP address on the ethernet device.
   *
   * @param gatewayAddress The IP address of the gateway.
   */
  void w5100_setGatewayAddress(ip_address_t gatewayAddress);

  /**
   * Attempts to open a connection on a specified socket. The socket must be
   * opened before this is attempted.
   *
   * @param socket The socket number (0-3) of the socket on which the operation
   *               will be performed.
   * @param attempts The number of attempts that will be made before which 
   *                 failure is reported.
   * 
   * @return SUCCESS if the operation was completed successfully. FAILED 
   *         otherwise. This will only happen if a connection could not be 
   *         opened after the specified number of attempts.
   */
  uint8 w5100_connect(uint8 socket, uint8 attempts);  
      
  /*****************************************************************************
   * Operations
   ****************************************************************************/      
  /**
   * Reset/un reset operations. Defined as separate macros because a delay may
   * be required between the two operations when used together.
   */
  #define W5100_RESET_ON           st( W5100_RESET_PIN = 0; )
  #define W5100_RESET_OFF          st( W5100_RESET_PIN = 1; )

  /**
   * Trigger the appropriate pins for a write operation. This macro will set
   * the chip select and write enable bits to 0, and then toggle them back to 1,
   * resulting in a 1->0->1 pulse on these bits.
   *
   * The st{} helper macro has not been used for performance reasons. This macro
   * can therefore not be used in if/else constructs reliably.
   */
  #define W5100_TRIGGER_WRITE      W5100_CONTROL_PORT &= \
                                            ~(W5100_WRITE_ENABLE_BM);\
                                      W5100_CONTROL_PORT |= \
                                              W5100_WRITE_ENABLE_BM;
             
  /**
   * Trigger the appropriate pins for a read operation. This macro will set
   * the chip select and read enable bits to 0, and then toggle them back to 1,
   * resulting in a 1->0->1 pulse on these bits.
   *
   * The st{} helper macro has not been used for performance reasons. This macro
   * can therefore not be used in if/else constructs reliably.
   */
  #define W5100_TRIGGER_READ(data) W5100_CONTROL_PORT &= \
                                            ~(W5100_READ_ENABLE_BM);\
                                      *data = W5100_DATA_PORT;\
                                      W5100_CONTROL_PORT |= \
                                              W5100_READ_ENABLE_BM;
  
  #ifdef __cplusplus
    }
  #endif

#endif
